package cms.factory.create;

import cms.utils.FileUtil;
import cms.utils.PathUtil;
import javassist.*;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ClassFile;
import javassist.bytecode.ConstPool;
import javassist.bytecode.annotation.*;
import lombok.extern.slf4j.Slf4j;

import javax.persistence.Index;
import javax.persistence.Table;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 分表Bean的基类
 */
@Slf4j
@Component
public class TableBeanCreate implements TableBean{

    private String buildClazzPath(Class<?> clazz, String separator) {
        String className = getPackageName(clazz);
        return StringUtils.join(StringUtils.split(className,"."),separator);
    }

    // 获取包路径
    private  String getPackageName(Class<?> clazz) {
        return clazz.getPackage().getName();
    }

    // 获取类名
    private  String getClassName(Class<?> clazz) {
        return clazz.getSimpleName();
    }

    // 获取类路径
    private  String getClass(Class<?> clazz) {
        return clazz.getName();
    }

    public void create(Class<?> clazz, int tableNumber,long serialVersionTag){

        ClassPool pool = getPool();
        //类的全部名称带包名
        String clazzFullName = getClass(clazz);
        String className =getClassName(clazz);
        //通过ClassPool生成一个public新类HistoryOrder.java
        CtClass ctClass = pool.makeClass(clazzFullName+"_"+tableNumber);
        try {
            // 父类
            ctClass.setSuperclass(pool.get(clazzFullName+"Entity"));
            // 添加接口
            ctClass.addInterface(pool.get("java.io.Serializable"));

            // 添加属性
            ctClass.addField(CtField.make("private static final long serialVersionUID = "+serialVersionTag+ tableNumber+"L;", ctClass));

            //写入注解(Annotation)
            ClassFile cf = ctClass.getClassFile();
            ConstPool cp = cf.getConstPool();

            //@Table(name="historyorder_0",indexes = {@Index(name="historyorder_idx", columnList="state,visible")})
            AnnotationsAttribute attr = new AnnotationsAttribute(cp, AnnotationsAttribute.visibleTag);

            //@Entity注解
            Annotation entityA = new Annotation("javax.persistence.Entity", cp);
            attr.addAnnotation(entityA);

            //@Table注解
            Annotation a = new Annotation("javax.persistence.Table", cp);
            a.addMemberValue("name", new StringMemberValue(className+"_"+tableNumber, cp));

            MemberValue[] vals = buildIdxFromClazz(clazz,className,cp,tableNumber);

            ArrayMemberValue arrayMemberValue=new ArrayMemberValue(cp);//数组类型
            arrayMemberValue.setValue(vals);

            a.addMemberValue("indexes", arrayMemberValue);//数组类型
            attr.addAnnotation(a);
            cf.addAttribute(attr);
            cf.setVersionToJava5();
        } catch (NotFoundException e) {
            //	e.printStackTrace();
            if (log.isErrorEnabled()) {
                log.error("创建积分日志bean",e);
            }
        }   catch (CannotCompileException e) {
            //	e.printStackTrace();
            if (log.isErrorEnabled()) {
                log.error("创建积分日志bean",e);
            }
        }


        //把生成的class文件写入文件
        byte[] byteArr;
        FileOutputStream fos = null;
        try {
            File file = new File(PathUtil.path()+File.separator+"WEB-INF"+File.separator+"classes"+File.separator+
                    buildClazzPath(clazz,File.separator)+File.separator+className+"_"+tableNumber+".class");
            log.info("初始化类路径={}",file.getAbsolutePath());
            if(file.exists()) {
                FileUtils.forceDelete(file);
            }
            byteArr = ctClass.toBytecode();
            //	fos = new FileOutputStream(new File("C://HistoryOrder_5.class"));
            fos = new FileOutputStream(file);
            fos.write(byteArr);
        } catch (IOException e) {
            //	e.printStackTrace();
            if (log.isErrorEnabled()) {
                log.error("创建"+clazzFullName+"bean",e);
            }
        } catch (CannotCompileException e) {
            //	e.printStackTrace();
            if (log.isErrorEnabled()) {
                log.error("创建"+clazzFullName+"bean",e);
            }
        } finally {
            if(fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    if (log.isErrorEnabled()) {
                        log.error("创建"+clazzFullName+"日志bean",e);
                    }
                }
            }
        }
    }

    private MemberValue[] buildIdxFromClazz(Class<?> clazz, String className, ConstPool cp, int tableNumber) {
        Table  table = clazz.getAnnotation(Table.class);
        Index[] indices = table.indexes();
        MemberValue[] vals = new MemberValue[indices.length];
        int i=0;
        int start = indices.length*tableNumber+1;
        for(Index index:indices){
            String columnList = index.columnList();
            Annotation indexA = new Annotation("javax.persistence.Index", cp);
            indexA.addMemberValue("name", new StringMemberValue(StringUtils.lowerCase(className+"_"+(i+start)+"_idx"), cp));
            indexA.addMemberValue("columnList", new StringMemberValue(columnList, cp));
            AnnotationMemberValue annotationMemberValue = new AnnotationMemberValue(cp);
            annotationMemberValue.setValue(indexA);
            vals[i]=annotationMemberValue;
            i++;
        }
        return vals;
    }

    protected ClassPool getPool(){
        //ClassPool：CtClass对象的容器
        ClassPool pool = ClassPool.getDefault();
        //    ClassClassPath classPath = new ClassClassPath(this.getClass());
        ClassClassPath classPath = new ClassClassPath(TableBeanCreate.class);
        pool.insertClassPath(classPath);
        return pool;
    }
}
